#include "Server.h"
#include "Logger.h"
#include "Threads.h"
#include "WorkQueue.h"
#include "Resolver.h"
#include <iostream>
#include <vector>
#include <errno.h>

class Request;

void Server::InitThreads()
{
	pthread_attr_init( &m_DispatcherAttr );
	pthread_attr_init( &m_ResolverAttr );
	pthread_attr_init( &m_AuthenticationAttr );
	pthread_attr_init( &m_WorkQueueAttr );

	pthread_attr_setdetachstate( &m_DispatcherAttr	, PTHREAD_CREATE_JOINABLE );
	pthread_attr_setdetachstate( &m_ResolverAttr	, PTHREAD_CREATE_JOINABLE );
	pthread_attr_setdetachstate( &m_WorkQueueAttr   , PTHREAD_CREATE_JOINABLE );
	pthread_attr_setdetachstate( &m_AuthenticationAttr, PTHREAD_CREATE_JOINABLE );

	pthread_mutex_init( &m_ResolveQueueMutex,	NULL );
	pthread_mutex_init( &m_WorkQueueMutex,   	NULL );
	pthread_mutex_init( &m_AuthMutex,			NULL );
	pthread_mutex_init( &m_FileMapMutex,		NULL );

	pthread_cond_init(&m_AuthResReady,NULL );
	pthread_cond_init(&m_AuthReqReady,NULL );
	pthread_cond_init(&m_ResolvQueueHasValues,	NULL );
	//pthread_cond_init(&m_WorkQueueHasValues,	NULL );



};
bool Server::StartServer()
{
	int success = SUCCESS;

	success += pthread_create( &m_AuthenticationThread , &m_AuthenticationAttr, Threads::AuthenticationThread , ( void* )this );
	success += pthread_create( &m_DispatcherThread	, &m_DispatcherAttr, Threads::DispatcherThread, ( void* )this  );
	success += pthread_create( &m_ResolverThread	, &m_ResolverAttr, Threads::ResolverThread, ( void* )this  );
	success += pthread_create( &m_WorkerThread[0]	, &m_WorkQueueAttr, Threads::Work, ( void* )this );
	success += pthread_create( &m_WorkerThread[1]	, &m_WorkQueueAttr, Threads::Work, ( void* )this );
	return ( success == SUCCESS );
};
Server::Server( Dispatcher& dis, Resolver& res,WorkQueue& wq,FileSystem& fs ,Logger& loogi, Logger& Err):LOGGER( loogi),ERRLOGGER(Err),dispatcher( dis ), resolver( res ), workQueue( wq ), fileSystem( fs )
{
	InitThreads();
};
Server::~Server()
{
	pthread_mutex_destroy( &m_ResolveQueueMutex );
	pthread_mutex_destroy( &m_WorkQueueMutex);
	pthread_mutex_destroy( &m_AuthMutex );
	pthread_mutex_destroy( &m_FileMapMutex );

	pthread_attr_destroy( &m_DispatcherAttr );
	pthread_attr_destroy( &m_ResolverAttr );

	pthread_cond_destroy( &m_AuthResReady );
	pthread_cond_destroy( &m_AuthReqReady );
	pthread_cond_destroy( &m_ResolvQueueHasValues);
	//pthread_cond_destroy( &m_WorkQueueHasValues	);

}
bool Server::LockResolveQueue()
{
	int status = pthread_mutex_trylock( &m_ResolveQueueMutex );

	switch( status )
	{
		case SUCCESS :
			//LOGGER<<"Resolve Queue Lock acquired \n";
			return true;
		case EINVAL:
			ERRLOGGER<<"ERROR: The value specified by Resolve Queue  mutex does not refer  to  an  initialized mutex object \n"
			<<"Please Check your initialization \n";
			return false;
		case EBUSY:
		case EAGAIN:
		default:
			return false;
	}
};
bool Server::UnLockResolveQueue()
{
	int status = pthread_mutex_unlock( &m_ResolveQueueMutex );

	switch( status )
	{
		case SUCCESS:
			//LOGGER<<"Server::UnLockResolveQueue Resolve queue Lock freed \n";
			return true;
		default:
			LOGGER<<"Server::UnLockResolveQueue UnLockResolveQueue failed\n";
			return false;
	}
};
bool Server::LockWorkQueue()
{
//	int status = pthread_mutex_trylock( &m_WorkQueueMutex);
	int status = pthread_mutex_lock( &m_WorkQueueMutex);

	switch( status )
	{
	case SUCCESS :
				//LOGGER<<"Work Queue Lock acquired \n";
				return true;
			case EINVAL:
				ERRLOGGER<<"ERROR: The value specified by Work Queue  mutex does not refer  to  an  initialized mutex object \n"
				<<"Please Check your initialization \n";
				return false;
			case EBUSY:
			case EAGAIN:
			default:
				return false;

	}
};
//bool	Server::SignalAuthCond()
//{
//
//	int success =  pthread_cond_signal( &m_AuthResReady );
//
//	return ( success == SUCCESS );
//
//};
//bool Server::WaitAuthCond()
//{
//	int success = pthread_cond_wait( &m_AuthResReady, &m_AuthMutex );
//	return ( success == SUCCESS );
//};
bool Server::UnLockWorkQueue()
{
	int status = pthread_mutex_unlock( &m_WorkQueueMutex );

		switch( status )
		{
			case SUCCESS:
				//LOGGER<<"Work queue Lock freed \n";
				return true;
			default:
				LOGGER<<"UnLock WorkQueue failed\n";
				return false;
		}
};
bool Server::LockAuth()
{

	//int status = pthread_mutex_trylock( &m_AuthMutex);
	int status = pthread_mutex_lock( &m_AuthMutex);

		switch( status )
		{
		case SUCCESS :
					//LOGGER<<"Server::LockAuth m_AuthMutex Lock acquired \n";
					return true;
				case EINVAL:
					ERRLOGGER<<"Server::LockAuth ERROR: The value specified by m_AuthMutex  mutex does not refer  to  an  initialized mutex object \n"
					<<"Please Check your initialization \n";
					return false;
				case EBUSY:
				case EAGAIN:
				default:
					sleep( 0.1 );
					return false;

		}

};
bool Server::UnLockAuth(){

	int status = pthread_mutex_unlock( &m_AuthMutex );

		switch( status )
		{
			case SUCCESS:
				//LOGGER<<"Server::UnLockAuth m_AuthMutex freed \n";
				return true;
			default:
				ERRLOGGER<<"Server::UnLockAuth m_AuthMutex failed\n";
				return false;
		}

};
bool Server::Authenticate( Request* pRequest )
{
//	while( !LockAuth() );
//	m_ReqAuth.m_pReq = pReq;
//	while( !UnLockAuth() );

	m_ReqAuth.m_pReq = pRequest;
	pthread_cond_signal( &m_AuthReqReady );
	int success = pthread_cond_wait( &m_AuthResReady, &m_AuthMutex );

	return ( success == SUCCESS );
};
//bool Server::RecvAuthRes( Request* pReq )
//{
//	bool recieved = false;
//
//	while( !LockAuth() );
//	if( m_ReqAuth.m_pReq == NULL )
//	{
//		recieved = true;
//	}
//	while( !UnLockAuth() );
//
//	return recieved;
//};
bool Server::LockFileMap()
{

	//int status = pthread_mutex_trylock( &m_FileMapMutex);
	int status = pthread_mutex_lock( &m_FileMapMutex);

	switch( status )
	{
	case SUCCESS :
				//LOGGER<<"m_FileMapMutex Lock acquired \n";
				return true;
			case EINVAL:
				ERRLOGGER<<"ERROR: The value specified by m_FileMapMutex  mutex does not refer  to  an  initialized mutex object \n"
				<<"Please Check your initialization \n";
				return false;
			case EBUSY:
			case EAGAIN:
			default:
				return false;

	}

};
bool Server::UnLockFileMap()
{
	int status = pthread_mutex_unlock( &m_FileMapMutex );

		switch( status )
		{
			case SUCCESS:
				//LOGGER<<"FileMapMutex freed \n";
				return true;
			default:
				LOGGER<<"FileMapMutex failed\n";
				return false;
		}
};

bool Server::InsertInResolveQueue( Request* pRequest )
{
	resolver.Enque( pRequest );
	int success = pthread_cond_signal( &m_ResolvQueueHasValues );
	return ( success == SUCCESS );
};
//bool	Server::InsertInWorkQueue( Request* pRequest )
//{
//	workQueue.Insert( pRequest );
//	int success = pthread_cond_signal( &m_WorkQueueHasValues );
//	return ( success == SUCCESS );
//};
